/***************************************************************************
 创建者: 华磊
 开始时间: 2019.3.9
 copyright: (C) 华友高科
 修改说明: (每次有修改就添加一条，带有 修改人，修改时间，修改描述)
 example (1) hualei 2017.5.8 类的具体实现代码编写

 ***************************************************************************/
#include "modbusserver.h"
#include <QModbusRtuSerialSlave>
#include <QModbusTcpServer>
#include <QUrl>
#include <qdebug.h>

ModbusServer::ModbusServer(ModbusConnection serverTypeIn, QString portNameIn, SerialSettings serialSettingIn,
                           QString ip_port_in,int serverAddressIdIn,int registerSizeIn)
{
    serverType=serverTypeIn;
    portName=portNameIn;
    serialSetting=serialSettingIn;
    ipAndPort=ip_port_in;
    serverAddressId=serverAddressIdIn;
    modbusDevice=NULL;
    registerSize.coilSize=registerSizeIn;
    registerSize.discreteInputSize=registerSizeIn;
    registerSize.inputRegisterSize=registerSizeIn;
    registerSize.holdingRegisterSize=registerSizeIn;
    initialModbusServer();



}

ModbusServer::~ModbusServer()
{
    if (modbusDevice)
        modbusDevice->disconnectDevice();
    delete modbusDevice;
}


int ModbusServer::setServerAddressId(int id)
{
    serverAddressId=id;
    return 1;
}

int ModbusServer::initialModbusServer()
{

    if (modbusDevice) {
        modbusDevice->disconnect();
        delete modbusDevice;
        modbusDevice = nullptr;
    }

   // ModbusConnection type = static_cast<ModbusConnection> (index);
    if (serverType == Serial) {
        modbusDevice = new QModbusRtuSerialSlave();
    } else if (serverType == Tcp) {
        modbusDevice = new QModbusTcpServer();

    }


        QModbusDataUnitMap reg;
        reg.insert(QModbusDataUnit::Coils, { QModbusDataUnit::Coils, 0, registerSize.coilSize });
        reg.insert(QModbusDataUnit::DiscreteInputs, { QModbusDataUnit::DiscreteInputs, 0, registerSize.discreteInputSize });
        reg.insert(QModbusDataUnit::InputRegisters, { QModbusDataUnit::InputRegisters, 0, registerSize.inputRegisterSize });
        reg.insert(QModbusDataUnit::HoldingRegisters, { QModbusDataUnit::HoldingRegisters, 0, registerSize.holdingRegisterSize });

        modbusDevice->setMap(reg);

        connect(modbusDevice, &QModbusServer::dataWritten,
                this, &ModbusServer::updateWidgets);
        connect(modbusDevice, &QModbusServer::stateChanged,
                this, &ModbusServer::onStateChanged);
        connect(modbusDevice, &QModbusServer::errorOccurred,
                this, &ModbusServer::handleDeviceError);



        setupDeviceData();

        return 1;

}


int ModbusServer::connectPort()
{
    bool intendToConnect = (modbusDevice->state() == QModbusDevice::UnconnectedState);


    if (intendToConnect) {
        if (serverType== Serial) {
            modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter,
                portName);
            modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter,
                serialSetting.parity);
            modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter,
                serialSetting.baud);
            modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter,
                serialSetting.dataBits);
            modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter,
                serialSetting.stopBits);
        } else {
             QUrl url = QUrl::fromUserInput(ipAndPort);
            modbusDevice->setConnectionParameter(QModbusDevice::NetworkPortParameter, url.port());
            modbusDevice->setConnectionParameter(QModbusDevice::NetworkAddressParameter, url.host());
        }
        modbusDevice->setServerAddress(serverAddressId);//simens plc需要使用0xff站号
       // modbusDevice->setServerAddress(0xff);
        if (!modbusDevice->connectDevice())
        {
            qDebug()<<modbusDevice->state();
            return -1;

        } else
        {
            qDebug()<<modbusDevice->state();
            return 1;
        }
    } else {
        return -1;
    }
    return 1;
}


int ModbusServer::disConnectPort()
{

    bool intendToConnect = (modbusDevice->state() == QModbusDevice::ConnectedState);


    if (intendToConnect)
    {
        modbusDevice->disconnectDevice();
        return 1;
    }
    else
    {
        return -1;
    }

    return -1;

}

int ModbusServer::getConnectState()
{
    qDebug()<<modbusDevice->state();
    return modbusDevice->state();
}
int ModbusServer::getModbusError()
{
    return modbusDevice->error();
}


void ModbusServer::handleDeviceError(QModbusDevice::Error newError)
{
    if (newError == QModbusDevice::NoError || !modbusDevice)
        return;

//    statusBar()->showMessage(modbusDevice->errorString(), 5000);
}

void ModbusServer::onStateChanged(int state)
{
    bool connected = (state != QModbusDevice::UnconnectedState);
//    ui->actionConnect->setEnabled(!connected);
//    ui->actionDisconnect->setEnabled(connected);

    if (state == QModbusDevice::UnconnectedState)
    {
//        ui->connectButton->setText(tr("Connect"));
        }
    else if (state == QModbusDevice::ConnectedState)
    {
//        ui->connectButton->setText(tr("Disconnect"));
        }
}


int ModbusServer::setCoilValue(int id,bool value)
{
    return setBit(id, QModbusDataUnit::Coils, value);
}

int ModbusServer::setDiscreteInputValue(int id,bool value)
{
    return setBit(id, QModbusDataUnit::DiscreteInputs, value);
}


int ModbusServer::setBit(int id, QModbusDataUnit::RegisterType table, bool value)
{
    if (!modbusDevice)
        return -1;

    if (!modbusDevice->setData(table, id, value))
        return -1;

    return 1;
}

int ModbusServer::setHoldingRegisters(int id,int value)
{
    if (!modbusDevice)
        return -1;


        bool ok = true;

            ok = modbusDevice->setData(QModbusDataUnit::HoldingRegisters, id, value);

        if (!ok)
        {
            return -1;
        }
        else
        {
            return 1;
        }
}

int ModbusServer::setInputRegister(int id, int value)
{
    if (!modbusDevice)
        return -1;


        bool ok = true;

            ok = modbusDevice->setData(QModbusDataUnit::InputRegisters, id, value);

        if (!ok)
        {
            return -1;
        }
        else
        {
            return 1;
        }

}

bool ModbusServer::getCoilValue(int id,quint16& valueReturn)
{
    return modbusDevice->data(QModbusDataUnit::Coils, id, &valueReturn);
}

bool ModbusServer::getDiscreteInputValue(int id,quint16& valueReturn)
{
    return modbusDevice->data(QModbusDataUnit::DiscreteInputs, id, &valueReturn);
}

bool ModbusServer::getHoldingRegisters(int id,quint16& valueReturn)
{
    return modbusDevice->data(QModbusDataUnit::HoldingRegisters, id, &valueReturn);
}

bool ModbusServer::getInputRegister(int id,quint16& valueReturn)
{
    return modbusDevice->data(QModbusDataUnit::InputRegisters, id, &valueReturn);
}

void ModbusServer::updateWidgets(QModbusDataUnit::RegisterType table, int address, int size)
{
//    for (int i = 0; i < size; ++i) {
//        quint16 value;
//        QString text;
//        switch (table) {
//        case QModbusDataUnit::Coils:
//            modbusDevice->data(QModbusDataUnit::Coils, address + i, &value);
//            coilButtons.button(address + i)->setChecked(value);
//            break;
//        case QModbusDataUnit::HoldingRegisters:
//            modbusDevice->data(QModbusDataUnit::HoldingRegisters, address + i, &value);
//            registers.value(QStringLiteral("holdReg_%1").arg(address + i))->setText(text
//                .setNum(value, 16));
//            break;
//        default:
//            break;
//        }
//    }
}



void ModbusServer::setupDeviceData()
{
    if (!modbusDevice)
        return;

    for (int i = 0; i < registerSize.coilSize; ++i)
        modbusDevice->setData(QModbusDataUnit::Coils, i, false);

    for (int i = 0; i < registerSize.discreteInputSize; ++i)
    {
        modbusDevice->setData(QModbusDataUnit::DiscreteInputs, i,false);
    }

    for (int i = 0; i < registerSize.holdingRegisterSize; ++i)
    {
        modbusDevice->setData(QModbusDataUnit::HoldingRegisters, i, 0);
    }

    for (int i = 0; i < registerSize.inputRegisterSize; ++i)
    {
        modbusDevice->setData(QModbusDataUnit::InputRegisters, i, 0);
    }


}

